﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "StructureGeneralParameterValidator.h"
#include "DbObjectUtils.h"
#include "GbmpBuiltInParameterDefinitions.h"
#include "IDocument.h"
#include "IElementParameters.h"
#include "IExternalObject.h"
#include "IGenericElement.h"
#include "IParameter.h"
#include "IParameterDefinitionLibrary.h"
#include "NewLevel.h"
#include "IPositionTwoAssociatedPlanes.h"
#include "IElementPosition.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"


using namespace gcmp;

DBOBJECT_DATA_DEFINE(StructureGeneralParameterValidator) 
{
}

OwnerPtr<IParameterValidator> StructureGeneralParameterValidator::Clone() const
{
    return NEW_AS_OWNER_PTR(StructureGeneralParameterValidator);
}

bool StructureGeneralParameterValidator::Validate(const IParameter* pNewParameter, const IElement* pElement, std::wstring* pErrorMessage) const
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pNewParameter && pElement, L"传入参数存在空值",L"GDMPLab",L"2024-03-30");

    const IElementParameters* pElementParameter = pElement->GetElementParameters();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pElementParameter, L"pElementParameters为空",L"GDMPLab",L"2024-03-30");

    if (pNewParameter->GetParameterDefinitionUid() == PARAMETER_UID(WallHeightBuiltInParameter))
    {
        return ValidateHeight(pNewParameter->GetValueAsDouble(), pErrorMessage);
    }

    auto getAssociatedLevelVal = [=](const UniIdentity& uid, bool CanEmpty = false, const IParameter* pNewParameter = nullptr)->double
    {
        const IDocument* pDoc = pElement->GetDocument();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"无法获取Document",L"GDMPLab",L"2024-03-30");
        const IGenericElement* pGenericElement = nullptr;
        if (!pNewParameter)
        {
            OwnerPtr<IParameter> associatedLevelParam = pElementParameter->GetParameterByUid(uid);
            DBG_WARN_AND_RETURN_FALSE_UNLESS(IParameter::IsValidParameter(associatedLevelParam), L"无法获取标高",L"GDMPLab",L"2024-03-30");
            pGenericElement = quick_cast<IGenericElement>(pDoc->GetElement(associatedLevelParam->GetValueAsElementId()));
        }
        else
        {
            pGenericElement = quick_cast<IGenericElement>(pDoc->GetElement(pNewParameter->GetValueAsElementId()));
        }

        if (pGenericElement == nullptr)
        {
            if (CanEmpty)
                return -1;
            DBG_WARN_AND_RETURN_UNLESS(false, 0, L"无法获取标高所在Element",L"GDMPLab",L"2024-03-30");
        }

        const IExternalObject* pExternalObject = pGenericElement->GetExternalObject();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pExternalObject, L"无法获取pExternalObject",L"GDMPLab",L"2024-03-30");
        const NewLevel* pNewLevel = quick_cast<NewLevel>(pExternalObject);
        DBG_WARN_AND_RETURN_UNLESS(pNewLevel, false, L"pNewLevel为空",L"GDMPLab",L"2024-03-30");
        return pNewLevel->GetElevation();
    };
    double associatedLevelVal, topAssociatedLevelVal, bottomOffsetVal, topOffsetVal;
    //底部标高
    associatedLevelVal = getAssociatedLevelVal(PARAMETER_UID(ElementAssociatedLevelBuiltInParameter));
    //顶部标高
    topAssociatedLevelVal = getAssociatedLevelVal(PARAMETER_UID(TopAssociatedLevelBuiltInParameter), true);
    //底部偏移
    OwnerPtr<IParameter> bottomOffsetParam = pElementParameter->GetParameterByUid(PARAMETER_UID(BottomOffsetBuiltInParameter));
    DBG_WARN_AND_RETURN_FALSE_UNLESS(IParameter::IsValidParameter(bottomOffsetParam), L"无法获取底部偏移",L"GDMPLab",L"2024-03-30");
    bottomOffsetVal = bottomOffsetParam->GetValueAsDouble();

    //顶部偏移
    OwnerPtr<IParameter> topOffsetParam = pElementParameter->GetParameterByUid(PARAMETER_UID(TopOffsetBuiltInParameter));
    DBG_WARN_AND_RETURN_FALSE_UNLESS(IParameter::IsValidParameter(topOffsetParam), L"无法获取顶部偏移",L"GDMPLab",L"2024-03-30");
    topOffsetVal = topOffsetParam->GetValueAsDouble();

    const UniIdentity& willValidParameterUID = pNewParameter->GetParameterDefinitionUid();
    if (willValidParameterUID == PARAMETER_UID(TopAssociatedLevelBuiltInParameter))
    {
        topAssociatedLevelVal = getAssociatedLevelVal(willValidParameterUID, true, pNewParameter);
        return ValidateLevel(associatedLevelVal, topAssociatedLevelVal, bottomOffsetVal, topOffsetVal, pErrorMessage);
    }

    if (willValidParameterUID == PARAMETER_UID(ElementAssociatedLevelBuiltInParameter))
    {
        associatedLevelVal = getAssociatedLevelVal(willValidParameterUID, false, pNewParameter);
        return ValidateLevel(associatedLevelVal, topAssociatedLevelVal, bottomOffsetVal, topOffsetVal, pErrorMessage);
    }

    if (willValidParameterUID == PARAMETER_UID(BottomOffsetBuiltInParameter))
    {
        bottomOffsetVal = pNewParameter->GetValueAsDouble();
        return ValidateOffset(associatedLevelVal, topAssociatedLevelVal, bottomOffsetVal, topOffsetVal, pErrorMessage, true);
    }

    if (willValidParameterUID == PARAMETER_UID(TopOffsetBuiltInParameter))
    {
        topOffsetVal = pNewParameter->GetValueAsDouble();
        return ValidateOffset(associatedLevelVal, topAssociatedLevelVal, bottomOffsetVal, topOffsetVal, pErrorMessage);
    }

    return true;
}

//标高验证
bool StructureGeneralParameterValidator::ValidateLevel(double associatedLevel, double topAssociatedLevel, double bottomOffset, double topOffset, std::wstring* pErrorMessage) const
{
    static std::wstring message(L"墙底部必须低于顶部，请重新选择。\n 点击确定后恢复至修改前选项");

    if (MathUtils::IsEqual(topAssociatedLevel, -1))
    {    //为空时默认大于底部标高, 这里的1目的是为了保证大于底部标高+偏移，没有实际意义。
        topAssociatedLevel = bottomOffset + associatedLevel + 1;
    }

    //底部标高必须低于顶部标高 
    if (!MathUtils::IsGreaterThan(topAssociatedLevel, associatedLevel))
    {
        if (pErrorMessage != nullptr)
            pErrorMessage->append(message);
        return false;
    }
    //底部标高+底部偏移必须低于顶部标高+顶部偏移
    if (!MathUtils::IsGreaterThan(topAssociatedLevel + topOffset, associatedLevel + bottomOffset) )
    {
        if (pErrorMessage != nullptr)
            pErrorMessage->append(message);
        return false;
    }
    return true;
}

//偏移验证
bool StructureGeneralParameterValidator::ValidateOffset(double associatedLevel, double topAssociatedLevel, double bottomOffset, double topOffset, std::wstring* pErrorMessage, bool isBottomOffset) const
{
    double willValid = isBottomOffset ? bottomOffset : topOffset;


    if (MathUtils::IsGreaterThan(-1000000, willValid) || !MathUtils::IsGreaterThan(1000000, willValid))
    {
        if (pErrorMessage != nullptr)
            pErrorMessage->append(L"请输入[-1000000, 1000000)内的数值");
        return false;
    }

    if (topAssociatedLevel == -1)
    {    //为空时默认大于底部标高, 这里的1目的是为了保证大于底部标高+偏移，没有实际意义。
        topAssociatedLevel = bottomOffset + associatedLevel + 1;
    }

    if (!MathUtils::IsGreaterThan(topAssociatedLevel + topOffset, bottomOffset + associatedLevel))
    {
        if (pErrorMessage != nullptr)
            pErrorMessage->append(L"墙底部必须低于顶部，请重新输入。\n 点击确定后恢复至修改前数值");
        return false;
    }
    return true;
}

//高度验证
bool StructureGeneralParameterValidator::ValidateHeight(double heightVal, std::wstring* pErrorMessage) const
{
    if (MathUtils::IsGreaterThan(0, heightVal) || !MathUtils::IsGreaterThan(1000000, heightVal))
    {
        if (pErrorMessage != nullptr)
        {
            pErrorMessage->append(L"请输入[0, 1000000)内的数值。\n点击确定后恢复至修改前数值。");
            return false;
        }
    }
    return true;
}
/////////////// ParameterValidatorCustomizedBehavior Impl ////////////////////////////////

DBOBJECT_DATA_DEFINE(ParameterValidatorCustomizedOverride) 
{
    m_ParameterUid = UniIdentity::InvalidUid;
}

ParameterValidatorCustomizedOverride::ParameterValidatorCustomizedOverride(UniIdentity parameterUid)
    : m_ParameterUid(parameterUid)
{

}

UniIdentity ParameterValidatorCustomizedOverride::GetUniIdentity() const
{
    return GetParameterUid__();
}

bool gcmp::ParameterValidatorCustomizedOverride::ShouldOverrideGetValidator() const
{
    return true;
}

const IParameterValidator * ParameterValidatorCustomizedOverride::GetValidator() const
{
    static StructureGeneralParameterValidator validator;
    return &validator;
}

/////////////// GeneralHeightBuiltInParameterOverride Impl ////////////////////////////////

DBOBJECT_DATA_DEFINE(GeneralHeightBuiltInParameterOverride)
{
    m_ParameterUid = UniIdentity::InvalidUid;
    m_OwnerElement = nullptr;
}

GeneralHeightBuiltInParameterOverride::GeneralHeightBuiltInParameterOverride(IElement* pElement, UniIdentity parameterUid)
    : m_ParameterUid(parameterUid)
    , m_OwnerElement(pElement)
{

}

UniIdentity GeneralHeightBuiltInParameterOverride::GetUniIdentity() const
{
    return GetParameterUid__();
}

bool GeneralHeightBuiltInParameterOverride::ShouldOverrideIsModifiable() const
{ 
    return true;
}

bool GeneralHeightBuiltInParameterOverride::IsModifiable() const
{
    if (GetOwnerElement() == nullptr)
        return true;

    const IElementPosition* pPosition = GetOwnerElement()->GetElementPosition();
    if (pPosition == nullptr)
        return true;

    auto pPositionAssociatedPlane = quick_cast<IPositionTwoAssociatedPlanes>(pPosition->GetPositionAssociatedPlane());
    if (pPositionAssociatedPlane == nullptr)
        return true;

    return !pPositionAssociatedPlane->GetTopAssociatedPlaneId().IsValid();
}

IElement* GeneralHeightBuiltInParameterOverride::GetOwnerElement(){ return m_OwnerElement; }
const IElement* GeneralHeightBuiltInParameterOverride:: GetOwnerElement() const { return m_OwnerElement; }
bool GeneralHeightBuiltInParameterOverride::SetOwnerElement(IElement* pElement)  { m_OwnerElement = pElement;  return true; }
